package com.cmc.cloud.cmclink.doc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.lock.annotation.Lock4j;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.VoyageBsaCbaTemplateErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.entity.VoyageBsaCbaDO;
import com.cmc.cloud.cmclink.doc.entity.VoyageBsaCbaDetailDO;
import com.cmc.cloud.cmclink.doc.mapper.VoyageBsaCbaDetailMapper;
import com.cmc.cloud.cmclink.doc.mapper.VoyageBsaCbaMapper;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbatemplatevo.VoyageBsaCbaTemplateBaseVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbatemplatevo.VoyageBsaCbaTemplateCreateReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbatemplatevo.VoyageBsaCbaTemplatePageReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbatemplatevo.VoyageBsaCbaTemplateUpdateReqVO;
import com.cmc.cloud.cmclink.doc.vo.voyagebsacbatemplatevo.VoyageCbaTemplateHistoryVO;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;

import java.util.*;
import java.util.stream.Collectors;

import com.cmc.cloud.cmclink.doc.service.VoyageBsaCbaTemplateService;
import com.cmc.cloud.cmclink.doc.entity.VoyageBsaCbaTemplateDO;
import com.cmc.cloud.cmclink.doc.mapper.VoyageBsaCbaTemplateMapper;


/**
 * 分类舱位自动批舱模版 Service 实现类
 *
 * @author 集运管理员
 */
@Service
@Validated
public class VoyageBsaCbaTemplateServiceImpl implements VoyageBsaCbaTemplateService {

    @Resource
    private VoyageBsaCbaTemplateMapper voyageBsaCbaTemplateMapper;

    @Resource
    private VoyageBsaCbaMapper voyageBsaCbaMapper;

    @Resource
    private VoyageBsaCbaDetailMapper voyageBsaCbaDetailMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaCbaUnique", keys = {"#createReqVO.getTemplateName", "#createReqVO.getPortCode"})
    public void createVoyageBsaCbaTemplate(VoyageBsaCbaTemplateCreateReqVO createReqVO) {
        // 插入
        validateUniqueExists(createReqVO, null);
        VoyageBsaCbaTemplateDO voyageBsaCbaTemplate = BeanUtil.copyProperties(createReqVO, VoyageBsaCbaTemplateDO.class);
        voyageBsaCbaTemplateMapper.insert(voyageBsaCbaTemplate);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Lock4j(name = "voyageBsaCbaUnique", keys = {"#updateReqVO.getTemplateName", "#updateReqVO.getPortCode"})
    public void updateVoyageBsaCbaTemplate(VoyageBsaCbaTemplateUpdateReqVO updateReqVO) {
        // 校验存在
        validateVoyageBsaCbaTemplateExists(updateReqVO.getId());
        validateUniqueExists(updateReqVO, updateReqVO.getId());
        // 更新
        VoyageBsaCbaTemplateDO updateObj = BeanUtil.copyProperties(updateReqVO, VoyageBsaCbaTemplateDO.class);
        voyageBsaCbaTemplateMapper.updateById(updateObj);
    }

    @Override
    public void deleteVoyageBsaCbaTemplate(Long id) {
        // 校验存在
        validateVoyageBsaCbaTemplateExists(id);
        // 删除
        voyageBsaCbaTemplateMapper.deleteById(id);
    }

    private void validateVoyageBsaCbaTemplateExists(Long id) {
        if (voyageBsaCbaTemplateMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(VoyageBsaCbaTemplateErrorCodeConstants.VOYAGE_BSA_CBA_TEMPLATE_NOT_EXISTS);
        }
    }

    private void validateUniqueExists(VoyageBsaCbaTemplateBaseVO vo, Long id) {
        LambdaQueryWrapperX<VoyageBsaCbaTemplateDO> queryWrapperX = new LambdaQueryWrapperX<VoyageBsaCbaTemplateDO>()
                .eqIfPresent(VoyageBsaCbaTemplateDO::getTemplateName, vo.getTemplateName())
                .eqIfPresent(VoyageBsaCbaTemplateDO::getPortCode, vo.getPortCode());
        if (id != null) {
            queryWrapperX.ne(VoyageBsaCbaTemplateDO::getId, id);
        }
        if (voyageBsaCbaTemplateMapper.selectCount(queryWrapperX) != 0L) {
            throw ServiceExceptionUtil.exception(VoyageBsaCbaTemplateErrorCodeConstants.VOYAGE_BSA_CBA_TEMPLATE_EXISTED);
        }
    }

    @Override
    public VoyageBsaCbaTemplateDO getVoyageBsaCbaTemplate(Long id) {
        return voyageBsaCbaTemplateMapper.selectById(id);
    }

    @Override
    public List<VoyageBsaCbaTemplateDO> getVoyageBsaCbaTemplateList(Collection<Long> ids) {
        return voyageBsaCbaTemplateMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<VoyageBsaCbaTemplateDO> getVoyageBsaCbaTemplatePage(VoyageBsaCbaTemplatePageReqVO reqVO) {
        LambdaQueryWrapperX<VoyageBsaCbaTemplateDO> queryWrapperX = new LambdaQueryWrapperX<VoyageBsaCbaTemplateDO>()
                .eqIfPresent(VoyageBsaCbaTemplateDO::getPortCode, reqVO.getPortCode())
                .likeIfPresent(VoyageBsaCbaTemplateDO::getTemplateName, reqVO.getTemplateName());
        return voyageBsaCbaTemplateMapper.selectPage(reqVO, queryWrapperX);
    }

    @Override
    public List<VoyageBsaCbaTemplateDO> getTemplateExistCba(VoyageBsaCbaTemplateBaseVO bsaCbaTemplateBaseVO) {
        return voyageBsaCbaTemplateMapper.getTemplateExistCba(bsaCbaTemplateBaseVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copyFromTemplateHistory(VoyageCbaTemplateHistoryVO templateHistoryVO) {
        if (StringUtils.equals(templateHistoryVO.getOriginalPortCode(), templateHistoryVO.getPortCode()) && StringUtils.equals(templateHistoryVO.getOriginalTemplateName(), templateHistoryVO.getTemplateName())) {
            throw ServiceExceptionUtil.exception(VoyageBsaCbaTemplateErrorCodeConstants.VOYAGE_BSA_CBA_TEMPLATE_EXISTED);
        }
        VoyageBsaCbaTemplateDO originalData = voyageBsaCbaTemplateMapper.selectOne(
                new LambdaQueryWrapperX<VoyageBsaCbaTemplateDO>().eq(VoyageBsaCbaTemplateDO::getPortCode, templateHistoryVO.getOriginalPortCode())
                        .eq(VoyageBsaCbaTemplateDO::getTemplateName, templateHistoryVO.getOriginalTemplateName()));
        if (ObjectUtils.isEmpty(originalData)) {
            throw ServiceExceptionUtil.exception(VoyageBsaCbaTemplateErrorCodeConstants.VOYAGE_BSA_CBA_TEMPLATE_NOT_EXISTS);
        }
        VoyageBsaCbaTemplateBaseVO createReqVO = BeanUtil.copyProperties(templateHistoryVO, VoyageBsaCbaTemplateBaseVO.class);
        validateUniqueExists(createReqVO, null);
        VoyageBsaCbaTemplateDO voyageBsaCbaTemplate = BeanUtil.copyProperties(createReqVO, VoyageBsaCbaTemplateDO.class);
        voyageBsaCbaTemplateMapper.insert(voyageBsaCbaTemplate);
        //原cba信息
        List<VoyageBsaCbaDO> bsaCbaDOList = voyageBsaCbaMapper.selectList(new LambdaQueryWrapper<VoyageBsaCbaDO>().eq(VoyageBsaCbaDO::getVoyageBsaId, originalData.getId()));
        if (CollectionUtil.isNotEmpty(bsaCbaDOList)) {
            List<VoyageBsaCbaDO> newDOList = CollectionUtil.newArrayList();
            for (VoyageBsaCbaDO entity : bsaCbaDOList) {
                VoyageBsaCbaDO bsaCbaDO = BeanUtil.copyProperties(entity, VoyageBsaCbaDO.class, "id", "createTime", "updateTime", "creator", "updater");
                bsaCbaDO.setVoyageBsaId(voyageBsaCbaTemplate.getId());
                newDOList.add(bsaCbaDO);
            }
            voyageBsaCbaMapper.insertBatch(newDOList);
            Set<Long> collect = bsaCbaDOList.stream().map(vo -> vo.getId()).collect(Collectors.toSet());
            //原 cba挂载的表达式信息
            List<VoyageBsaCbaDetailDO> detailDOList = voyageBsaCbaDetailMapper.selectList(new LambdaQueryWrapperX<VoyageBsaCbaDetailDO>().inIfPresent(VoyageBsaCbaDetailDO::getVoyageBsaCbaId, collect));
            if (CollectionUtil.isNotEmpty(detailDOList)) {
                Map<String, Long> cbaNewMap = newDOList.stream()
                        .collect(Collectors.toMap(
                                p -> p.getAllocationSpace() + "_" + p.getSpaceTypeCode(),
                                VoyageBsaCbaDO::getId,
                                (existing, replacement) -> existing
                                // 处理键冲突的策略
                        ));
                Map<Long, Long> idMap = new HashMap<>(16);
                bsaCbaDOList.stream().forEach(a -> {
                    idMap.put(a.getId(), cbaNewMap.get(a.getAllocationSpace() + "_" + a.getSpaceTypeCode()));
                });
                List<VoyageBsaCbaDetailDO> newCbaDetailList = CollectionUtil.newArrayList();
                for (VoyageBsaCbaDetailDO entity : detailDOList) {
                    VoyageBsaCbaDetailDO voyageBsaCbaDetailDO = new VoyageBsaCbaDetailDO();
                    voyageBsaCbaDetailDO.setJsonString(entity.getJsonString());
                    voyageBsaCbaDetailDO.setVoyageBsaCbaId(idMap.get(entity.getVoyageBsaCbaId()));
                    newCbaDetailList.add(voyageBsaCbaDetailDO);
                }
                voyageBsaCbaDetailMapper.insertBatch(newCbaDetailList);
            }
        }
    }
}
